callee和caller
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | function inner(){
 console.log(arguments.callee);
 
 console.log(arguments.callee.caller);
 
 console.log(inner.caller);
 
 }
 
 function outer(){
 
 inner();
 
 }
 
 outer();
 
 | 
callee放回正在执行的函数本身的引用,它是arguments的一个属性
caller 返回一个函数的引用,这个函数调用了当前的函数。
严格模式下,不允许访问arguments.callee和arguments.caller属性,主要体现在arguments.[[Get]]内部方法
严格模式下,arguments,arguments.callee,arguments.caller,arguments.callee.caller也不允许再被赋值。如下代码所示:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | 'use strict';
 
 
 void function fn(a) {
 
 console.log(arguments[0]);
 
 a = 2;
 
 console.log(arguments[0]);
 
 }(1);
 
 
 
 void function(){
 
 console.log('hi');
 
 }();
 
 | 
在使用立即执行的函数表达式时,可以利用 void 运算符让 JavaScript 引擎把一个函数识别成函数表达式而不是函数声明(语句)。
实参和形参
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | var add = function (a,b) {
 console.log(arguments.length);
 
 console.log(arguments.callee.length);
 
 };
 
 add(1,2,3);
 
 | 
Array.prototype.slice.call(arguments)
slice有两个用法,一个是String.slice,一个是Array.slice,第一个返回的是字符串,第二个返回的是数组。
Array.prototype.slice.call(arguments)能够将arguments转成数组,那么就是arguments.toArray().slice();
因为arguments并不是真正的数组对象,只是与数组类似而已,所以它并没有slice这个方法,而Array.prototype.slice.call(arguments)可以理解成是将arguments转换成一个数组对象,让arguments具有slice()方法。 比如:
| 12
 3
 
 | var arr = [1,2,3,4];
 console.log(Array.prototype.slice.call(arr,2));
 
 | 
同样,还有Array.prototype.forEach.call(),forEach() 方法让数组的每一项都执行一次给定的函数。   
String()
我们可以用String()来确定某一变量是否是null或者undefined
| 12
 3
 4
 5
 6
 
 | var a , b = null;
 
 String(a);
 
 String(b);
 
 | 
直接调用String()作为方法时,将会执行类型转换,返回经过toString(value)得到的字符串字面量(与new String()不同),或者空字符串(’’).
window 对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | <script>
 (function () {
 
 var root = this;
 
 console.log(root);
 
 })();
 
 </script>
 
 | 
打开控制台,你可以看到window对象的一系列属性和方法:
new function
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | var a = function () {};
 
 console.log(typeof a);
 
 
 var b = new function () {};
 
 console.log(typeof b);
 
 
 var c = new Function ();
 
 console.log(typeof c);
 
 | 
new function 是一个JavaScript中用户自定义的对象    
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | var obj = function (name) {
 this.name = name;
 
 };
 
 var b = new obj('trigkit4');
 
 console.log(b.name);
 
 | 
js中的false和true
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | 
 
 console.log(Boolean(''));
 
 console.log(Boolean(null));
 
 console.log(Boolean(undefined));
 
 console.log(Boolean(0));
 
 console.log(Boolean(false));
 
 console.log(Boolean(NaN));
 
 
 
 
 console.log(Boolean(' '));
 
 console.log(Boolean('NaN'));
 
 | 
除了false,null,undefined,空字符串'',数字0和NaN以外,其他所有值都被当做是真,包括true,字符串""里包含的值,以及所有对象。
valueOf() 和 toString()
valueOf()和toString()方法是所有ECMAScript对象拥有的内置方法。操作对象时,valueOf()和toString()会被隐式的调用。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | 
 
 console.log(Object.valueOf());
 
 console.log(Object.prototype.valueOf());
 
 var boo = new Boolean(1);
 
 console.log(boo.valueOf());
 
 
 var bar = Boolean(0);
 console.log(bar.valueOf());
 
 
 var str = String("trigkit4");
 console.log(str.valueOf());
 console.log(null.valueOf());
 console.log(undefined.valueOf());
 
 
 
 
 
 console.log(Object.prototype.toString());
 
 console.log(Object.toString());
 
 Object.prototype.toString.call(null);
 
 Object.prototype.toString.call(undefined);
 
 {a: 'b'}.toString();
 
 | 
valueOf()方法的目的是将对象转换成最有意义的原始值([[PrimitiveValue]])。即ECMAScript的5种基本类型中的三种,布尔值、数字、字符串。
当valueOf方法被调用时,会调用内置的ToObject,并将this作为参数传进去。ToObject检测会根据参数类型进行数值的转换:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | Undefined - 抛出TypeError异常
 Null - 抛出TypeError异常
 
 Boolean - 创建一个Boolean对象,调用ToBoolean生成[[PrimitiveValue]]
 
 Number - 创建一个Number对象,调用ToNumber生成[[PrimitiveValue]]
 
 String - 创建一个String对象,调用ToString生成[[PrimitiveValue]]
 
 Object - 对象本身
 
 | 
ECMAScript对象的大多数操作的转换结果是字符串,这两个方法的结果是相同的。但是如果操作的对象为Number、Boolean或者Date,结果就不同了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | var foo = {
 toString: function () {
 
 return "foo";
 
 },
 
 valueOf: function () {
 
 return 5;
 
 }
 
 };
 
 
 
 console.log(foo + "bar");
 
 console.log([foo, "bar"].join(""));
 
 | 
在这个上下文环境中,我们使用"+"操作符来使字符串连接,但是,foo并没有使用toString来转换成字符串,它使用valueOf转换成一个number,这并不是我们想要的,
但它是如何工作的,这是+运算符的算术和字符串连接超载的副作用。"+"操作符有一个明确的处理过程:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | 1.评估左手侧,并得到该值。
 
 2.评估右手侧,并获得该值。
 
 3.同时在左手和右手侧调用ToPrimitive(无提示)
 
 4.如果任何原始值是一个字符串,然后跳到7。
 
 5.在这两个值调用ToNumber。
 
 6.返回值的总和。
 
 7.在这两个值调用toString。
 
 8.返回的值连接起来
 
 | 
setInterval和setTimeout
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | alert(1);
 
 setTimeout("alert(2)", 0);
 
 alert(3);
 
 执行顺序为:1,3,2,虽然延时了0ms
 
 setTimeout 0
 
 后面的语句执行完再执行本身,这时就可以用到setTimeout延时0ms来实现了。
 
 | 
cookie的创建和删除
cookie可以跨越一个域名下的多个网页,但不能跨越多个域名使用。
| 12
 3
 4
 
 | document.cookie = “user = 值;expires = 过期时间;path = 路径访问;
 
 domain = 域名访问;secure = 安全的https限制通信"
 
 | 
cookie的创建方式
设置cookie我们一般都封装成一个函数:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | function addCookie(sName,sValue,day) {
 
 var expireDate = new Date();
 
 expireDate.setDate(expireDate.getDate()+day);;
 
 
 
 document.cookie = escape(sName) + '=' + escape(sValue) +';
 
 expires=' + expireDate.toGMTString();6
 
 }
 
 | 
删除cookie
为了删除一个cookie,可以将其过期时间设定为一个过去的时间,例如:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | 
 
 var date=new Date();
 
 
 
 date.setTime(date.getTime()-10000);
 
 
 
 document.cookie="userId=828; expires="+date.toGMTString();
 
 | 
给cookie设置终止日期
到现在为止,所有的cookie都是单会话cookie,即浏览器关闭后这些cookie将会丢失,事实上这些cookie仅仅是存储在内存中,而没有建立相应的硬盘文件。
在实际开发中,cookie常常需要长期保存,例如保存用户登录的状态。这可以用下面的选项来实现:
| 1
 | document.cookie="userId=828; expiress=GMT_String";
 | 
其中GMT_String是以GMT格式表示的时间字符串,这条语句就是将userId这个cookie设置为GMT_String表示的过期时间,超过这个时间,cookie将消失,不可访问。例如:如果要将cookie设置为10天后过期,可以这样实现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | <script language="JavaScript" type="text/javascript">
 
 
 var date=new Date();
 
 var expiresDays=10;
 
 
 
 date.setTime(date.getTime()+expiresDays*24*3600*1000);
 
 
 
 document.cookie="userId=828; userName=hulk; expires="+date.toGMTString();
 
 </script>
 
 | 
对象和函数可以如数组一样,用属性名或方法名作为下标来访问:
对象的创建
| 12
 3
 4
 5
 6
 7
 8
 
 | 
 
 function MyFunc(){}
 
 var obj1 = new MyFunc();
 
 var obj2 = new MyFunc;
 
 | 
可以把上面的代码改写成这种等价形式:
| 12
 3
 4
 5
 6
 
 | function MyFunc(){};
 
 var obj1 = {};
 
 MyFunc.call(obj1);
 
 | 
作用域
通过自执行的匿名函数你可以把所有原本属于全局的变量都隐藏起来:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | 
 
 (function () {
 
 
 
 var msg = "Thanks for visiting";
 
 
 window.onunload = function () {
 
 console.log(msg);
 
 };
 
 })();
 
 | 
上下文对象是通过this变量体现的,这个变量永远指向当前代码所处的对象中。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | var obj = {
 
 yes : function(){
 
 
 
 this.val = true;
 
 },
 
 no : function(){
 
 this.val = false;
 
 }
 
 };
 
 console.log(obj.val == null);
 
 
 
 obj.yes();
 
 console.log(obj.val == true);
 
 | 
String 原型方法的扩展
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 |     
 String.prototype.Regular = function(reg){
 
 var result = true;
 
 if(this.length > 0){
 
 if(!reg.test(this)){
 
 result = false;
 
 }
 
 }
 
 return result;
 
 }
 
 
 
 
 
 String.prototype.trim = function () {
 
 return this.replace(/(^\s*)|(\s*$)/g,'');
 
 };
 
 | 
^表示字符串必须以后面的规则开头,而(^\s*) 表示的就是以0个空格或者多个空格开头,后面的(\s*$) 的意思就是, 以0个空格或者多个空格结尾。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 |   
 String.prototype.isNull = function(){
 
 return this.trim().length == 0 ? true : false;
 
 }
 
 
 
 
 String.prototype.isVersion = function(){
 
 var reg = /^([a-zA-Z_])([a-zA-Z0-9_.])*$/;
 
 return this.Regular(reg);
 
 }
 
 
 
 
 String.prototype.isString = function(){
 
 var reg = /^[^']*$/;
 
 return this.Regular(reg);
 
 }
 
 
 
 
 
 String.prototype.isLetter = function(){
 
 var reg = /^[a-zA-Z]+$/;
 
 return this.Regular(reg);
 
 }
 
 | 
constructor属性
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | function User(){}
 
 var me = new User();
 
 console.log(me.constructor);
 
 
 
 
 
 var you = new me.constructor();
 
 console.log(me.constructor == you.constructor);
 
 | 
Object.create
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | function Parent(){}
 var o = Object.create(Parent.prototype);
 
 console.log(o instanceof Parent);
 
 console.log(o instanceof Object);
 
 console.log(Object.prototype.toString.call(o));
 
 | 
“数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。 如果未指定最后三个特性,则它们默认为 false。
| 12
 3
 4
 5
 6
 7
 8
 
 | function Parent(){}
 
 var o = Object.create(Parent);
 
 console.log(o instanceof Parent);
 
 console.log(o instanceof Object);
 
 | 
另外一个实例
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 
 | var book1 = {
 
 title:"JS高级程序设计",
 
 pages : 1001,
 
 getTitle:function(){
 
 console.log(this.title);
 
 }
 
 };
 
 var book2 = Object.create(book1,{
 
 
 
 title:{
 
 configurable:true,
 
 enumerable:true,
 
 value:"JS权威指南",
 
 wratable:true
 
 }
 
 });
 
 book1.getTitle();
 
 book2.getTitle();
 
 
 
 console.log(book1.hasOwnProperty("getTitle"));
 
 console.log('pages' in book2);
 
 console.log(book2.hasOwnProperty("getTitle"));
 
 console.log(book1.isPrototypeOf(book2));
 
 | 
再看另一个例子:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | function Constructor(){}
 
 obj = new Constructor();
 
 
 
 obj = Object.create(Constructor.prototype);
 
 console.log(obj);
 
 console.log(Object.create(Constructor.prototype));
 
 
 
 console.log(obj instanceof Constructor);
 
 console.log(Constructor.prototype.isPrototypeOf(obj));
 
 
 
 var foo;
 
 foo = {};
 
 
 
 foo = Object.create(Object.prototype);
 
 | 
另外:
| 12
 3
 
 | console.log(Object.prototype);
 console.log(Object.create(Object.prototype));
 
 | 
通过Object.create(Object.prototype) 创建的实例对象就继承了Object原型下的属性和方法。
javascript所有function类型的对象都有一个prototype属性。这个prototype属性本身又是一个object类型的对象,原型对象都包含一个指向构造函数的指针,而每一个实例也都包含一个指向原型对象内部的指针。
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
prototype原型
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | function User(){}
 
 var u1 = new User();
 
 console.log(u1.prototype);
 
 console.log(User.prototype);
 
 console.log(u1.__proto__);
 
 
 
 
 
 User.prototype = {
 
 name : "trigkit4",
 
 age : 22
 
 };
 
 | 
使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,但还是有些区别,字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | function User(){}
 
 User.prototype = {
 
 name : "trigkit4",
 
 age : 22
 
 };
 
 var u1 = new User();
 
 console.log(u1.constructor);
 
 console.log(u1 instanceof User);
 
 console.log(u1.constructor == User);
 
 console.log(u1.constructor == Object);
 
 
 
 
 
 User.prototype = {
 
 constructor : User;
 
 }
 
 | 
字面量方式为什么constructor会指向Object?因为User.prototype = {};这种写法其实就是创建了一个新对象:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | function User(){
 
 User.prototype = {
 
 constructor : User
 
 };
 
 var u1 = new User();
 
 console.log(User.constructor);
 
 console.log(u1.constructor == User);
 
 | 
另一个例子:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | (function () {
 
 
 
 console.log(Object.prototype);
 
 console.log(Array.prototype);
 
 console.log(Array.prototype.push);
 
 console.log(Function.prototype);
 
 console.log(Function.prototype.bind);
 
 
 })();
 
 | 
Object.prototype.toString
在toString()方法被调用时,会执行下面的操作步骤:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 如果this的值为undefined,则返回"[object Undefined]".
 
 如果this的值为null,则返回"[object Null]".
 
 让O成为调用ToObject(this)的结果.
 
 让class成为O的内部属性[[Class]]的值.
 
 返回三个字符串"[object ", class, 以及 "]"连接后的新字符串.
 
 | 
由于 JavaScript 中一切都是对象,任何都不例外,对所有值类型应用Object.prototype.toString.call()
方法结果如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | console.log(Object.prototype.toString.call(123))
 
 console.log(Object.prototype.toString.call('123'))
 
 console.log(Object.prototype.toString.call(undefined))
 
 console.log(Object.prototype.toString.call(true))
 
 console.log(Object.prototype.toString.call({}))
 
 console.log(Object.prototype.toString.call([]))
 
 console.log(Object.prototype.toString.call(function(){}))
 
 | 
所有类型都会得到不同的字符串,几乎完美。
在JavaScript中,想要判断某个对象值属于哪种内置类型,最靠谱的做法就是通过Object.prototype.toString方法.
面向对象
下面是来自Prototype.js的一段代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | 
 
 var Class = {
 
 
 
 create: function(){
 
 
 
 return function () {
 
 
 
 this.initialize.apply(this,arguments);
 
 }
 
 }
 
 };
 
 
 
 
 
 Object.extend = function (destination,source) {
 
 
 
 for(property in source){
 
 
 
 destination[property] = source[property];
 
 }
 
 };
 
 | 
成员操作符
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | function aFunc(){}
 
 
 
 aFunc.oProperty = "函数的一个属性";
 
 aFunc.aMethod = function(){
 
 console.log("函数的一个方法");
 
 };
 
 
 console.log(aFunc["oProperty"]);
 
 console.log(aFunc["aMethod"]());
 
 
 
 
 for(var s in aFunc){
 
 console.log(s + "is a "+typeof(aFunc[s]));
 
 }
 
 | 
特权方法与私有方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 
 | function Constructor(msg)
 this.Message = msg;
 
 
 
 //私有属性
 
 var separator = '-';
 
 var owner = this;
 
 
 
 //私有方法
 
 function alertMessage(){
 
 console.log(owner.Message);
 
 }
 
 alertMessage();
 
 
 
 
 
 this.aptMessage = function (str)
 
 this.Message += separator + str;
 
 alertMessage();
 
 }
 
 }
 
 
 
 
 
 Constructor.prototype.clearMessage = function (str)
 
 this.Message = '';
 
 };
 
 
 
 
 
 Constructor.name = 'trigkit4';
 
 
 
 
 
 Constructor.alertName = function (name)
 
 console.log(this.name);
 
 };
 
 | 
特权方法是指在构造函数的作用域中使用this关键字定义的方法;与私有方法不同,特权方法能够被公开访问,而且还能够访问私有成员。
由于私有和特权成员在函数的内部,因此它们会被带到函数的每个实例中。   
公有的原型成员是对象蓝图的一部分,适用于通过new关键字实例化的该对象的每个实例 静态成员只适用于对象的一个特殊实例
使用对象字面量语法来向prototype属性添加所有公有成员:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | function Constructor(){
 
 
 }
 
 
 
 
 
 Constructor.prototype = {
 
 propertyA: 'value1',
 
 propertyB: 'value2',
 
 methodA: function(){},
 
 methodB: function(){}
 
 };
 
 | 
删除不要的节点
DOM 元素在浏览器中所占用的空间是非常大的,要及时回收不用的节点:
| 12
 3
 4
 5
 6
 
 | var node = parentNode.removeChild(node);
 
 node = null;
 
 CollectGarbage();
 
 |